CONTENTS | INDEX | PREV | NEXT
 FUNCTION
 Make Utility

 SYNOPSIS
 dmake [file]

 DESCRIPTION
 Make utilities automate complex compiles.  Makefiles can be
 considered recipes for complex programs.  Makefiles contain
 "dependencies," which are rules that say things like "if this header
 file changes, recompile this C file."

 The idea with DMake is to provide a powerful make utility through
 general features rather than specialized hacks.  DMake is governed by
 a few simple rules that can be combined into incredibly powerful
 operations.

 Generally you simply run DMake and have a list of dependencies in
 your DMakefile which DMake then executes.  The DMakefile may contain
 three different kinds of lines:

 1) COMMENTS -- Any line beginning with a '#' is a comment and ignored

 # This DMakefile generates an executable for fubar
 # The compiler options are as follows ...

 1) ASSIGNMENTS -- Any line of the form SYMBOL = ...  is considered an
    assignment.  Any variable references from within the assignment
    will be resolved immediately.

 CFLAGS= -r SRCS= x.c y.c z.c

 1) DEPENDENCIES: -- A line containing a list of symbols, a colon, and
    more symbols is assumed to be a dependency.  Note that you cannot
    have a raw filename with a colon in it as that confuses DMake.
    Instead, use an ASSIGNMENT variable.

 Following the dependency line is zero or more command lines --
 commands to run to resolve the dependency, terminated with a blank
 line.

 || NOTE: Not only is a zero-command dependency allowed, it is
 || sometimes necessary.

 A particular destination may have only ONE command list so if you
 have something like

 a.o : a.c

 with a command list to compile the source into an object you can also
 have another dependency such as 'a.o : defs.h' which would NOT have
 any associated command list.

 dst1 ...  dstN : src1 ...  srcN command1 command2 ...
 dst1 ...  dstN : src1 ...  srcN command1 command2 ...

 Finally, note that a dst* or src* symbol does not need to be a
 filename.  It is perfectly valid to make up dummy names which are
 then used as the lhs of a dependency that collects other dependencies
 together.

 DEPENDENCIES
 When declaring dependencies you may use four different forms.  The
 first form is to have a single destination and several sources.  This
 is interpreted to mean that ALL the sources must be resolved before
 the single destination can be resolved via the command list for the
 dependency.  The special variable, %(left), is set to the dst symbol
 and the special variable %(right) is set to ALL of the src symbols

 For example, this form would be used to indicate that an executable
 depends on all the objects being resolved before you can run the
 link.

 dst : src1 src2 src3 ...  srcN

 The second form is the most useful in that it allows you to specify
 multiple 1 : 1 dependencies.  Thus, you can specify, for example,
 that each object file depends on its source file counterpart for ALL
 the files in your project on a single line and have a single command
 list representing what to do (to compile a source file into an
 object, say).

 In this case %(left) and %(right) are set to each dst* : src* pair
 individually and the command list is run for any individual pair that
 is out of date.

 dst1 dst2 dst3 ...  dstN : src1 src2 src3 ...  srcN

 The next form may be used to specify that many files depend on one
 file being resolved.  An example of usage would be to make all the
 object files depend on one header file.  The command list, if any, is
 run for each dst* : src pair with %(left) set to the current dst* and
 %(right) set to the single source.

 dst1 dst2 dst3 ...  dstN : src

 The last form is esoteric but sometimes useful.  EACH dst* on the
 left hand side depends on the entire right hand side.  You can have
 an arbitrary number of symbols on either side.  %(left) will be set
 to a particular DST while %(right) will be set to all of the SRCs.

 for example, you could specify $(OBJS) :: $(HDRS) -- make all objects
 depend on all headers causing a recompile to occur if any header is
 modified.

 dst1 dst2 dst3 ...  dstN :: src1 src2 ...  srcI

 WILDCARDS
 DMake's most powerful feature is an easy to use file list replacement
 through options in a variable specification.  You may insert the
 contents of any variable using the form:

 $(SYMBOL)

 Furthermore, you can make modifications to the contents of the
 variable on the fly using:

 $(SYMBOL:wildcard)

 only those files which match wildcard

 $(SYMBOL:wildcard:wildcard)

 matching files and also do a conversion

 Simple */? wildcarding is used.  A wildcard may contain a colon or
 other punctuation but if it does you MUST surround it with quotes.
 Here is a quick example:

 SRCS= a.c b.c c.c d.c xx.a
 OBJS= $(SRCS:*.c:"dtmp:%1.o")

 all: echo $(OBJS)

 Will Produce

 dtmp:a.o dtmp:b.o dtmp:c.o dtmp:d.o

 The first wildcard specification restricts which files from the list
 are to be taken -- 'xx.a' was ignored, as you can see.  Each '*' or
 '?' in the first wildcard specification corresponds to %N
 specifications in the second wildcard specification.  You can
 prepend, insert, or append text and freely mix or ignore items
 matched to create your destination file list.

 This capability allows you to specify your source files EXACTLY ONCE
 in the DMakefile and then use the file munging capability to convert
 them to the object file list, etc...

 You can embed variables within variables as with the following
 example (note that this time xx.a is included):

 OD= dtmp:fubar/
 SRCS= a.c b.c c.c d.c xx.a
 OBJS= $(SRCS:*.?:"$(OD)%1.o")

 all: echo $(OBJS)

 Will produce

 dtmp:fubar/a.o dtmp:fubar/b.o dtmp:fubar/c.o
 dtmp:fubar/d.o dtmp:fubar/xx.o

 As a side note, you may also specify '?' and '*' in the destination
 wildcard.  These are considered dummies and are equivalent to %N
 where N is incremented from 1..9 for each '?' or '*' encountered.

 You can use the capability anywhere in the DMakefile.  Another common
 thing to do is restrict your link line to include only the object
 files and skip the headers:

 $(EXE) : $(PROTOS) $(OBJS) $(HDRS)
 dcc %(right:*.o) -o %(left)

 ENVIRONMENT VARIABLES
 2.0 local variables and 1.3/2.0 ENV: variables are fully accessible.
 Under 2.0 you can also modify local variables on the fly.
 DMake-specific variables override 2.0 local variables override ENV:
 variables.

 Under 2.0, any command containing <, >, `, or |, or is an alias, will
 be run with System().  Thus, such commands may not be used to modify
 local variables or the local environment.  Also, such commands cannot
 be ^C'd due to the way AmigaDOS works.

 EXAMPLE
 The following is an example dmakefile.  The variable $(FILES) is set
 to "main input output".  The next two variables are constructed from
 $(FILES).  The command $(FILES:*:"*.c") tells dmake to take $(FILES),
 look up each item ":*", and append two characters ":*.c".  The
 results of the conversions are listed above.  This unique feature of
 dmake makes for very elegant DMakeFiles.

 The first rule is the default rule, executed if you just type dmake.
 The rule, "sample:", states that the resulting program, "sample", is
 made up from the files listed in $(FILE_OBJECTS). If the date on
 "sample" is older than any dates in $(FILE_OBJECTS), the rule will
 execute.

 In turn, the next rule states that $(FILE_OBJECTS) ("main.o input.o
 output.o") are made from $(FILE_SOURCES) ("main.c intput.c
 output.c").  If any of the .o files are older than the corresponding
 .c file, the rule executes.

 In short, the makefile is a description of how source files inter
 depend.  When any file changes, dmake figures the minimum number of
 steps to regenerate the final result.  If you change just "input.c",
 only "input.c" will recompile.

 The last rule, "clean:", has no dependencies (nothing on the right
 side of the :).  When executed, this rule deletes all the
 compiler-generated files, but not the source code. To execute this
 rule, type "dmake clean".  Any number of rules may exist in a single
 DMakeFile.

                   :     DMakeFile - generic
 ------------------------------+-------------------------------------
 FILES = main input output     : Equals "main input output" Set to
 FILE_SOURCES =            : "main.c input.c output.c" Set to
 $(FILES:*:*.c") FILE_OBJECTS  : "t:main.o t:input.o t:output.o"
 = $(FILES:*:"t:*.o)           :
 ------------------------------+-------------------------------------
 sample: $(FILE_OBJECTS)     dcc  : Rule: sample is made from
 $(FILE_OBJECTS) -o sample     : FILE_OBJECTS (defined above as
                   : "t:main.o t:input.o t:output.o")
 ------------------------------+-------------------------------------
 $(FILE_OBJECTS) :         : Rule: FILE_OBJECTS are made from
 $(FILE_SOURCES)     dcc -c       : FILE_SOURCES (see above).
 %(right) -o %(left)       :
 ------------------------------+-------------------------------------
 clean:            delete  : Rule: "dmake clean" executes this
 $(FILES) $(FILE_OBJECTS)      : delete command.
 ------------------------------+-------------------------------------

 LINE CONTINUATION AND ESCAPES
 Any line may be continued by terminating it with a backslash ''.  It
 is possible to escape the special characters '$' and '%' by doubling
 them though this is only necessary if an open-parenthesis follows the
 '$' or '%' and you do not want it interpreted as a variable.

 It is possible to escape ':' and other special characters by
 assigning them (or a string containing them) to a variable

 COMMAND SHELL
 Under 2.0 commands that do not contain any sort of redirection are
 run with RunCommand().  If a command is an alias or there is some
 sort of redirection in the arguments it will be run with System().

 Under 1.3 everything is run with Execute()

 ADVANCED CAPABILITIES
 Now, you may have noted earlier that I said you could not have any
 given left-hand-side with more then one command list.  Take, for
 example:
   
 a.o : a.c dcc %(right) -o %(left)
   
 a.o : defs.h <--- illegal to put command list here
   
 Actually, it isn't illegal.  When DMake encounters a dependency
 without a command list it will automatically 'force' the next higher
 level dependency of the same left-hand-side.  Therefore if you do not
 have a command list for the lower level left-hand-side things work as
 you expect.  Note that this requires all such null dependencies to
 exist AFTER the one that has the command list.
   
 If you do have two or more command lists for the same left-hand-side
 they will run independent of each other according to their individual
 right hand sides.  If several command lists apply then their order of
 execution will be bottom-up

 T FOR EXISTENCE
 ther advanced feature quite useful in fully automating the
 pilation process is the ability to create a directory tree on the
 .  That is, if you have a projects called 'fubar' and want the
 ects to go into the directory DTMP:fubar/ you might want to have a
 endency that creates DTMP:fubar if it does not already exist.

  dtmp:fubar
 X) : $(XX) makedir %(left)